Basic

import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render(
  <h1>Hello, World!</h1>,
  document.querySelector('#root')
);

render some JSX to the <div id="root"></div> in your HTML

JSX

  • HTML you can directly write HTML in JSX and assign it to a variable

    如果有大段HTML,用圆括号扩起来

  • JS Expressions use any Javascript expression in a curly braces { 2 + 2 }, { user.name }, { showMenu() } epxression can even be used in attributes

  • JSX use camelCase property in HTML class => classNametabindex => tabIndex

  • JSX will be compiled as object

Render

ReactDOM.render(element,DOM);

React 的 Element 是不可变的,每次UI的变化都需要重新调用 ReactDOM.render() 方法

function tick () {
  const element = <h3>It is { new Date().toLocaleTimeString() }</h3>
  ReactDOM.render(
    element,
    document.querySelector('#root')
  );
}

setInterval(tick, 1000);

在实际操作中,只会调用一次Render 方法,并且通过Stateful Component 去改变UI

Components

**Component 接受 props 参数并返回相应的 UI **

主要有两种相同的定义模式,分别如下:

Functional

function Welcome (props) {
    return <h1>Welcome {props.name}</h1>
}
// HTML
<Welcome name='Ethan'>

ES6 Class

class Welcome extends React.Component {
    render() {
      return <h1>Welcome, {this.props.name}</h1>
    }
}
// HTML
<Welcome name='Ethan'></Welcome>

Props

React 约定不能在组建内部修改传入的 props

Render

在 component 的 Render 方法中,可以添加逻辑代码甚至变量:

class LoginControl extends React.Components {
  constructor(){};
  render () {
    const isLoggedIn = this.state.isLoggedIn;
    let button = null;
    
    if (isLoggedIn) {
      button = <LogoutBtn onClick={this.loggedOut}></LogoutBtn>;
    } else {
      button = <LogoutBtn onClick={this.loggedIn}></LogoutBtn>;
    }
    
    return (
      <div>
        {button}
      </div>
    )
  }
}

Inline & operator

curly brace and operator (&&, ?😃 can also make condition

class Mailbox extends React.Component {
  constructor(props){super(props)};
  return (
    <div>
      {
      	props.messageNum > 0 &&
        <h1>You have {props.messageNum} unread message</h1>
      }  
  	</div>
  )
}

ReactDOM.render(
  <Mailbox messageNum=3></Mailbox>,
  DomElement
);

Render Nothing

if sometimes you want to hide the component, simply set a condition to retrun null

##Status & Lifecycle

status is similar to props, but it’s private and fully controlled by component

but for data not shown in UI, you shouldn’t put it in status.

class Clock extends React.Component {
  constructor (props) {
    super(props);
    this.state = {date: new Date()}
  }

  componentDidMount () {
    this.timerID = setInterval(
      () => this.tick(),
      100
    )
  }

  componentWillUnmount () {
    clearInterval(this.timerID);
  }

  tick () {
    this.setState({
      date: new Date()
    })
  }

  render () {
    return <h3>It is {this.state.date.toLocaleString()}. </h3>
  }
}
  • State have to use class mode
  • Props have to use the super() 类似于 Parent.call(this),用于继承父类this
  • Changing state has to use this.setState({a: '123'})
  • If state based on previous state, use this.setState((prevState, props)=>({a: prevState.a + 1}))
  • State can pass down to child component as props
  • Data can only flows down, called unidirectiona data flow

Lifecycle Hooks

componentDidMount

componentWillUnmount

Events

React use camelCase event handler rather than lowercase

onclick => onClick

We should not call addEventListener in React, instead, we should provide a listener when the element in initially rendered.

  • 如果要在 event function 中使用 this,需要在constructor 里绑定this this.eventHandler = this.eventHandler.bind(this) 或者使用 ES6 尖头函数自动绑定this,如下例

    handleClick = () => {
        this.setState();
    }
    

Lists & Keys

const listItem = [1, 2, 3, 4, 5].map((num) => {
    <li>{num}</li>
});

return (<ul>{listItem}</ul>);

but most times we should add keys for whatever list so React can detect the change of the list node.

we use index for keys in the case below (not recommend because slow) but if possible we should use id property of data.

const listItem = [1, 2, 3, 4, 5].map((num, index) => {
    <li key={index}>{num}</li>
  	//<li key={num.id}>{num.number}</li>
  	//<li key={num.toString()}>{num}</li>
});

return (<ul>{listItem}</ul>);

Keys have to be identical among siblings

Form

similar to Angular & Vue, use state to gather data

class NameForm extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
          nameValue: ''
      };
    }
  
    handleChange = (e) => this.setState({nameValue: e.target.value})
	handleSubmit = (e) => {
      // do something
      e.preventDefault();
    }
    
    render() {
      return (
      	<form onSubmit={this.handleSubmit}>
          Name: <input  type="text" 
                  		value={this.state.value}
                  		onChange={this.handleChange}
                  		/>
        </form>
      )
    }
}

State 提升

在有多个 input 互相嵌套的情况下,我们尽量把 state 尽可能的提升到高的组建层,然后通过 props 向下传递数据

Composition

like the slug in Vue, the props.children is specifically used as slug for other component.

function FancyBorder(props) {
  return (
  	<div className={'FancyBorder-' + props.color}>
      {props.children}
    </div>
  )
}

function WelcomeDialog() {
  return (
  	<FancyBorder color='blue'>
      <h1>something show in the props.children</h1>
    </FancyBorder>
  )
}

If multiple holes needed, we can pass the react element as object directly

function FancyBorder(props) {
  return (
    <div>
      <div className="section1">{props.section1}</div>
      <div className="section2">{props.section2}</div>
    </div>
  )
}

function App() {
  return (
  	<FancyBorder 
      section1={<contracts />}
      section2={<Chat />}
  )
}